﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using WarOfDev.Web.Models;
using WarOfDev.EF;
using System.Configuration;
using System.DirectoryServices;
using WarOfDev.Core.StateManagentHelpers;
using WarOfDev.Core.ExceptionHandling.ExceptionDetails;
using WarOfDev.Core.ExceptionHandling.Exceptions;
using WarOfDev.Core.Configuration;

namespace WarOfDev.Web.Controllers
{
    [Authorize]
    public class AccountController : BaseController
    {
        private static readonly string conn = ConfigurationManager.ConnectionStrings["WarDevEntities"].ToString();
        //
        // GET: /Account/Login
        [AllowAnonymous]
        public ActionResult Login(string returnUrl)
        {
            if (!Request.IsAuthenticated || !(SessionHelper<Developer>.GetCurrentUser(HttpContext) is Developer))
            {
                var registedUer = this.GetRegisterModel(HttpContext.Request.LogonUserIdentity.Name);
                using (var db = new WarDevEntities(conn))
                {
                    var existDev = db.Developers.FirstOrDefault(d => (d.DomainAccount == registedUer.DomainAccount) && d.IsLocked == false);

                    if (existDev == null)
                    {
                        return View();
                    }
                    else
                    {
                        var userToken = db.Users.Include("Roles").FirstOrDefault(u => u.UserId == existDev.Id);

                        var permissionValues = db.Roles.AsEnumerable().Where(r => userToken.Roles.Where(ur => ur.RoleId == r.Id && ur.UserId == userToken.Id).Count() > 0).Select(r => r.Permissions).ToArray();

                        if (permissionValues == null || permissionValues.Length == 0)
                        {
                            throw new WofException<FrontendDetail>("no permission", null, new FrontendDetail(10101, "no permission"));
                        }
                        else
                        {
                            var permissions = string.Join(",", permissionValues).Split(',').Distinct().Select(p => Convert.ToInt32(p));

                            userToken.Permissions = db.Permissions.AsEnumerable().Where(p => permissions.Contains(p.PermissionValue)).ToList();

                            FormsAuthentication.SetAuthCookie(existDev.DomainAccount, true);
                            SessionHelper<Developer>.SetCurrentUser(HttpContext, existDev);
                            SecurityTokenHelper<User>.SetSecurityToken(HttpContext, userToken);

                            if (string.IsNullOrEmpty(returnUrl))
                            {
                                return RedirectToAction("Index", "Home");
                            }
                            else
                            {
                                return RedirectToAction("Index", "Home");
                            }
                        }
                    }
                }

            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }

        //
        // POST: /Account/Login

        [AllowAnonymous]
        [HttpPost]
        public ActionResult Login(LoginModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (Membership.ValidateUser(model.UserName, model.Password))
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                    if (Url.IsLocalUrl(returnUrl))
                    {
                        return RedirectToAction("Register");
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "The user name or password provided is incorrect.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }


        public ActionResult CurrentInfo()
        {
            var info=new DeveloperModel();

            using(var db= new WarOfDev.EF.WarDevEntities())
            {
                var currentDeveloper = db.Developers.Single(d => d.Id == this.CurrentUser.Id);
                info.ExperienceValue =  currentDeveloper.ExperienceValue;
                info.NickName = currentDeveloper.NickName;
                info.Level = currentDeveloper.GameLevel;

                info.LevelName = ExperienceValueSetting.GetEntityByLevel(info.Level).LevelName;
                info.CurrentLevelPeakExperienceValue = ExperienceValueSetting.GetEntityByLevel(info.Level).LimitedExperienceValue;
                info.GoUpRate = (int)(((decimal)info.ExperienceValue / info.CurrentLevelPeakExperienceValue) * 100);
            }

            return PartialView("DeveloperInfo", info);
        }

        //
        // GET: /Account/LogOff

        public ActionResult LogOff()
        {
            FormsAuthentication.SignOut();
            SessionHelper<User>.ClearSession(HttpContext);
            return RedirectToAction("Index", "Home");
        }

        [AllowAnonymous]
        public ActionResult Register()
        {
            return View(this.GetRegisterModel(HttpContext.Request.LogonUserIdentity.Name));
        }


        [AllowAnonymous]
        [HttpPost]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                var dev = new Developer
                {
                    Id = Guid.NewGuid().ToString(),
                    NickName = model.NickName,
                    TrueName = model.TrueName,
                    DomainAccount = model.DomainAccount,
                    CreatedOn = DateTime.Now,
                    ModifiedOn = DateTime.Now,
                    GameLevel=DefaultExperienceValueSetting.InitialGameLevel,
                    ExperienceValue=DefaultExperienceValueSetting.InitialExperience


                };

                var user = new User
                {
                    Id = Guid.NewGuid().ToString(),
                    UserId = dev.Id,
                    UserName = model.DomainAccount,
                    Password = "12345678",
                    Description = model.NickName,
                    CreatedOn = DateTime.Now,
                    ModifiedOn = DateTime.Now,
                    IsLocked = false
                };

                using (var context = new WarDevEntities())
                {
                    var existDev = context.Developers.FirstOrDefault(d => d.DomainAccount == dev.DomainAccount);
                    if (existDev == null)
                    {
                        context.AddToDevelopers(dev);
                        var existUser = context.Users.FirstOrDefault(u => u.UserName == dev.DomainAccount);
                        if (existUser == null)
                        {
                            context.AddToUsers(user);
                        }
                        else
                        {
                            context.Attach(existUser);
                            existUser.UserId = dev.Id;
                            existUser.ModifiedOn = DateTime.Now;
                            context.ObjectStateManager.ChangeObjectState(existUser, System.Data.EntityState.Modified);
                        }

                        context.SaveChanges();
                    }
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        public ActionResult ChangePassword()
        {
            return View();
        }

        //
        // POST: /Account/ChangePassword
        [HttpPost]
        public ActionResult ChangePassword(ChangePasswordModel model)
        {
            if (ModelState.IsValid)
            {

                // ChangePassword will throw an exception rather
                // than return false in certain failure scenarios.
                bool changePasswordSucceeded;
                try
                {
                    MembershipUser currentUser = Membership.GetUser(User.Identity.Name, userIsOnline: true);
                    changePasswordSucceeded = currentUser.ChangePassword(model.OldPassword, model.NewPassword);
                }
                catch (Exception)
                {
                    changePasswordSucceeded = false;
                }

                if (changePasswordSucceeded)
                {
                    return RedirectToAction("ChangePasswordSuccess");
                }
                else
                {
                    ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        public ActionResult ChangePasswordSuccess()
        {
            return View();
        }

        private IEnumerable<string> GetErrorsFromModelState()
        {
            return ModelState.SelectMany(x => x.Value.Errors.Select(error => error.ErrorMessage));
        }

        private RegisterModel GetRegisterModel(string account)
        {
            if (account.IndexOf("\\") < 0)
            {
                account = "@\\@";
            }

            var domain = account.Split('\\')[0];
            var userName = account.Split('\\')[1];

            string filter = string.Format("(&(ObjectClass={0})(sAMAccountName={1}))", "user", userName);
            string[] properties = new string[] { "fullname" };

            DirectoryEntry adRoot = new DirectoryEntry("LDAP://" + domain, null, null, AuthenticationTypes.Secure);
            DirectorySearcher searcher = new DirectorySearcher(adRoot);
            searcher.SearchScope = SearchScope.Subtree;
            searcher.ReferralChasing = ReferralChasingOption.All;
            searcher.PropertiesToLoad.AddRange(properties);
            searcher.Filter = filter;

            SearchResult result = searcher.FindOne();
            DirectoryEntry directory = result.GetDirectoryEntry();

            string displayName = directory.Properties["displayName"][0].ToString();
            string firstName = directory.Properties["givenName"][0].ToString();
            string lastName = directory.Properties["sn"][0].ToString();
            string email = directory.Properties["mail"][0].ToString();

            RegisterModel user = new RegisterModel();
            user.DomainAccount = account;
            user.NickName = displayName;
            user.TrueName = firstName + " " + lastName;
            return user;
        }
    }
}
